#include "..\include\imp_typedefine.h"
#include "..\include\imp_io_wrapper.h"
#include "..\include\imp_pictext_wrapper.h"

#define M_SOF0  0xffc0
#define M_DHT   0xffc4
#define M_EOI   0xffd9
#define M_SOS   0xffda
#define M_DQT   0xffdb
#define M_DRI   0xffdd
#define M_APP0  0xffe0
#define M_SOI   0xffd8

#define WIDTHBYTES(i) (((i+31)>>5)<<2)

const static int imejpeg_Zig_Zag[8][8]={{0,1,5,6,14,15,27,28},
						{2,4,7,13,16,26,29,42},
						{3,8,12,17,25,30,41,43},
						{9,11,18,24,37,40,44,53},
						{10,19,23,32,39,45,52,54},
						{20,22,33,38,46,51,55,60},
						{21,34,37,47,50,56,59,61},
						{35,36,48,49,57,58,62,63}
};

#define W1 2841 /* 2048*sqrt(2)*cos(1*pi/16) */
#define W2 2676 /* 2048*sqrt(2)*cos(2*pi/16) */
#define W3 2408 /* 2048*sqrt(2)*cos(3*pi/16) */
#define W5 1609 /* 2048*sqrt(2)*cos(5*pi/16) */
#define W6 1108 /* 2048*sqrt(2)*cos(6*pi/16) */
#define W7 565  /* 2048*sqrt(2)*cos(7*pi/16) */

const Int8 imejpeg_And[9] = {0,1,3,7,0xf,0x1f,0x3f,0x7f,0xff};
const Int8 imejpeg_JFIF_TAG[5] = {0x4A, 0x46, 0x49, 0x46, 0x00};

typedef struct _t_jpeg_dec
{
	Int16 SampRate_Y_H,SampRate_Y_V;
	Int16 SampRate_U_H,SampRate_U_V;
	Int16 SampRate_V_H,SampRate_V_V;
	Int16 H_YtoU,V_YtoU,H_YtoV,V_YtoV;
	Int16 Y_in_MCU,U_in_MCU,V_in_MCU;
	Int16 qt_table[3][64];
	Int16 comp_num;
	UInt8 comp_index[3];
	Int8 YDcIndex,YAcIndex,UVDcIndex,UVAcIndex;
	Int8 HufTabIndex;
	Int16 *YQtTable,*UQtTable,*VQtTable;
	Int16 code_pos_table[4][16],code_len_table[4][16];
	UInt16 code_value_table[4][256];
	UInt16 huf_max_value[4][16],huf_min_value[4][16];
	Int16 BitPos,CurByte;
	Int16 rrun,vvalue;
	Int16 MCUBuffer[10*64];
	Int32 QtZzMCUBuffer[10*64];
	Int16 BlockBuffer[64];
	Int16 ycoef,ucoef,vcoef;
	Int8 IntervalFlag;
	Int16 interval;
	Int32 Y[4*64],U[4*64],V[4*64];
	Int32 sizei,sizej;
	Int16 restart;
	Int32 iclip[1024];
	Int32 *iclp;
	Int32 ImgWidth, ImgHeight;
	ImpFileHandle fp;
	ImpFileHandle out_fp;
	Int8* jpg2bmp_buf;
	Int8 *in_buf, *out_buf;
	Int32 in_len, in_pos, out_pos;
	Int32 dec_type_file;
}t_jpeg_dec;

typedef struct _t_bitmap_fileheader {
	Int16 bfType; 
	Int32 bfSize; 
	Int16 bfReserved1; 
	Int16 bfReserved2; 
	Int32 bfOffBits; 
}t_imevui_bitmap_fileheader; 

typedef struct _t_bitmap_infoheader { 
	Int32 biSize; 
	Int32 biWidth; 
	Int32 biHeight; 
	Int16 biPlanes; 
	Int16 biBitCount;
	Int32 biCompression; 
	Int32 biSizeImage; 
	Int32 biXPelsPerMeter; 
	Int32 biYPelsPerMeter; 
	Int32 biClrUsed; 
	Int32 biClrImportant; 
}t_imevui_bitmap_infoheader; 

static UInt8 imejpeg_read_byte(t_jpeg_dec *inst)
{
	UInt8 buf = 0;
	if(inst->dec_type_file)
	{
		if(IMP_FileRead((Int8 *)&buf, 1, inst->fp) <= 0)
			return 0;
		}
	else
	{
		buf = inst->in_buf[inst->in_pos++];
	}
	return buf;
}
static void imejpeg_seek(t_jpeg_dec *inst, Int32 offset)
{
	if(inst->dec_type_file)
	{
		IMP_FileSeek(inst->fp, offset, IMPFile_Seek_Current);
	}
	else
	{
		inst->in_pos += offset;
	}
}

static void imepict_jpeg_output(t_jpeg_dec *inst, Int8 *src_buf, Int32 src_len)
{
	if(inst->dec_type_file)
	{
		IMP_FileWrite(src_buf, src_len, inst->out_fp);
	}
	else
	{
		IMP_Memcpy(inst->out_buf+inst->out_pos, src_buf, src_len);
		inst->out_pos += src_len;
	}
}

static UInt16 imejpeg_get16le(t_jpeg_dec *inst)
{
	UInt16 val = 0;
	val = imejpeg_read_byte(inst);
	val |= imejpeg_read_byte(inst) << 8;
	return val;
}
static UInt16 imejpeg_get16be(t_jpeg_dec *inst)
{
	UInt16 val = 0;
	val = imejpeg_read_byte(inst) << 8;
	val |= imejpeg_read_byte(inst);
	return val;
}
static Int32 imejpeg_decode_init_fast_idct(t_jpeg_dec *inst)
{
	Int16 i;

	inst->iclp = inst->iclip+512;
	for (i= -512; i<512; i++)
		inst->iclp[i] = (i<-256) ? -256 : ((i>255) ? 255 : i);

	return 1;
}
static UInt8 imejpeg_decode_mcu_getbyte(t_jpeg_dec *inst)
{
	UInt8 byte = imejpeg_read_byte(inst);
	if(byte == 0xff)
		imejpeg_read_byte(inst);
	inst->BitPos = 8;
	inst->CurByte = byte;
	return byte;
}
static Int32 imejpeg_decode_mcu_element(t_jpeg_dec *inst)
{
	Int32 thiscode,tempcode;
	UInt16 temp,valueex;
	Int16 codelen;
	UInt8 hufexbyte,runsize,tempsize,sign;
	UInt8 newbyte,lastbyte;

	if(inst->BitPos>=1)
	{
		inst->BitPos--;
		thiscode=(UInt8)inst->CurByte>>inst->BitPos;
		inst->CurByte = inst->CurByte&imejpeg_And[inst->BitPos];
	}
	else
	{
		lastbyte=imejpeg_decode_mcu_getbyte(inst);
		inst->BitPos--;
		newbyte = inst->CurByte&imejpeg_And[inst->BitPos];
		thiscode = lastbyte>>7;
		inst->CurByte=newbyte;
	}
	codelen=1;
	while ((thiscode<inst->huf_min_value[inst->HufTabIndex][codelen-1])||
		(inst->code_len_table[inst->HufTabIndex][codelen-1]==0)||
		(thiscode > inst->huf_max_value[inst->HufTabIndex][codelen-1]))
	{
		if(inst->BitPos>=1)
		{
			inst->BitPos--;
			tempcode = (UInt8)inst->CurByte>>inst->BitPos;
			inst->CurByte = inst->CurByte&imejpeg_And[inst->BitPos];
		}
		else
		{
			lastbyte=imejpeg_decode_mcu_getbyte(inst);
			inst->BitPos--;
			newbyte = inst->CurByte&imejpeg_And[inst->BitPos];
			tempcode=(UInt8)lastbyte>>7;
			inst->CurByte = newbyte;
		}
		thiscode=(thiscode<<1)+tempcode;
		codelen++;
		if(codelen>16)
			return 0;
	}  //while
	temp=thiscode - inst->huf_min_value[inst->HufTabIndex][codelen-1] + inst->code_pos_table[inst->HufTabIndex][codelen-1];
	hufexbyte = (UInt8)inst->code_value_table[inst->HufTabIndex][temp];
	inst->rrun = (Int16)(hufexbyte>>4);
	runsize = hufexbyte&0x0f;
	if(runsize==0)
	{
		inst->vvalue=0;
		return 1;
	}
	tempsize = runsize;
	if(inst->BitPos >= runsize)
	{
		inst->BitPos -= runsize;
		valueex = (UInt8)inst->CurByte >> inst->BitPos;
		inst->CurByte = inst->CurByte&imejpeg_And[inst->BitPos];
	}
	else
	{
		valueex = inst->CurByte;
		tempsize -= inst->BitPos;
		while(tempsize>8)
		{
			lastbyte=imejpeg_decode_mcu_getbyte(inst);
			valueex=(valueex<<8)+(UInt8)lastbyte;
			tempsize-=8;
		}  //while
		lastbyte = imejpeg_decode_mcu_getbyte(inst);
		inst->BitPos -= tempsize;
		valueex=(valueex<<tempsize)+(lastbyte >> inst->BitPos);
		inst->CurByte = lastbyte&imejpeg_And[inst->BitPos];
	}  //else
	sign=valueex>>(runsize-1);
	if(sign)
		inst->vvalue=valueex;
	else{
		valueex=valueex^0xffff;
		temp=0xffff<<runsize;
		inst->vvalue=-(Int16)(valueex^temp);
	}
	return 1;
}
static Int32 imejpeg_decode_mcu_hufblock(t_jpeg_dec *inst, Int8 dchufindex, Int8 achufindex)
{
	Int16 count=0;
	Int16 i;

	//dc
	inst->HufTabIndex = dchufindex;
	if(!imejpeg_decode_mcu_element(inst))
		return 0;
	inst->BlockBuffer[count++] = inst->vvalue;
	//ac
	inst->HufTabIndex = achufindex;
	while (count<64){
		if(!imejpeg_decode_mcu_element(inst))
			return 0;
		if ((inst->rrun==0)&&(inst->vvalue==0)){
			for (i=count;i<64;i++)
				inst->BlockBuffer[i]=0;
			count=64;
		}
		else{
			for (i=0;i<inst->rrun;i++)
				inst->BlockBuffer[count++]=0;
			inst->BlockBuffer[count++] = inst->vvalue;
		}
	}
	return 1;
}
static Int32 imejpeg_decode_mcu_block(t_jpeg_dec *inst)
{
	Int16 *lpMCUBuffer;
	Int16 i,j;

	if (inst->IntervalFlag)
	{
		imejpeg_get16be(inst);
		inst->ycoef = inst->ucoef = inst->vcoef = 0;
		inst->BitPos=0;
		inst->CurByte=0;
	}
	switch(inst->comp_num)
	{
	case 3:
		lpMCUBuffer = inst->MCUBuffer;
		for (i=0;i<inst->SampRate_Y_H*inst->SampRate_Y_V;i++)  //Y
		{
			if(!imejpeg_decode_mcu_hufblock(inst, inst->YDcIndex,inst->YAcIndex))
				return 0;
			inst->BlockBuffer[0] = inst->BlockBuffer[0] + inst->ycoef;
			inst->ycoef = inst->BlockBuffer[0];
			for (j=0;j<64;j++)
				*lpMCUBuffer++=inst->BlockBuffer[j];
		}
		for (i=0;i<inst->SampRate_U_H*inst->SampRate_U_V;i++)  //U
		{
			if(!imejpeg_decode_mcu_hufblock(inst, inst->UVDcIndex,inst->UVAcIndex))
				return 0;
			inst->BlockBuffer[0] = inst->BlockBuffer[0] + inst->ucoef;
			inst->ucoef = inst->BlockBuffer[0];
			for (j=0;j<64;j++)
				*lpMCUBuffer++=inst->BlockBuffer[j];
		}
		for (i=0;i<inst->SampRate_V_H*inst->SampRate_V_V;i++)  //V
		{
			if(!imejpeg_decode_mcu_hufblock(inst, inst->UVDcIndex,inst->UVAcIndex))
				return 0;
			inst->BlockBuffer[0] = inst->BlockBuffer[0] + inst->vcoef;
			inst->vcoef = inst->BlockBuffer[0];
			for (j=0;j<64;j++)
				*lpMCUBuffer++=inst->BlockBuffer[j];
		}
		break;
	case 1:
		lpMCUBuffer = inst->MCUBuffer;
		if(!imejpeg_decode_mcu_hufblock(inst, inst->YDcIndex,inst->YAcIndex))
			return 0;
		inst->BlockBuffer[0] = inst->BlockBuffer[0] + inst->ycoef;
		inst->ycoef = inst->BlockBuffer[0];
		for (j=0;j<64;j++)
			*lpMCUBuffer++=inst->BlockBuffer[j];
		for (i=0;i<128;i++)
			*lpMCUBuffer++=0;
		break;
	default:
		IMP_Assert(0, "error component num %d", inst->comp_num);
		break;
	}
	return 1;
}

static void imejpeg_idctrow(int * blk)
{
	int x0, x1, x2, x3, x4, x5, x6, x7, x8;
	//intcut
	if (!((x1 = blk[4]<<11) | (x2 = blk[6]) | (x3 = blk[2]) |
		(x4 = blk[1]) | (x5 = blk[7]) | (x6 = blk[5]) | (x7 = blk[3])))
	{
		blk[0]=blk[1]=blk[2]=blk[3]=blk[4]=blk[5]=blk[6]=blk[7]=blk[0]<<3;
		return;
	}
	x0 = (blk[0]<<11) + 128; // for proper rounding in the fourth stage 
	//first stage
	x8 = W7*(x4+x5);
	x4 = x8 + (W1-W7)*x4;
	x5 = x8 - (W1+W7)*x5;
	x8 = W3*(x6+x7);
	x6 = x8 - (W3-W5)*x6;
	x7 = x8 - (W3+W5)*x7;
	//second stage
	x8 = x0 + x1;
	x0 -= x1;
	x1 = W6*(x3+x2);
	x2 = x1 - (W2+W6)*x2;
	x3 = x1 + (W2-W6)*x3;
	x1 = x4 + x6;
	x4 -= x6;
	x6 = x5 + x7;
	x5 -= x7;
	//third stage
	x7 = x8 + x3;
	x8 -= x3;
	x3 = x0 + x2;
	x0 -= x2;
	x2 = (181*(x4+x5)+128)>>8;
	x4 = (181*(x4-x5)+128)>>8;
	//fourth stage
	blk[0] = (x7+x1)>>8;
	blk[1] = (x3+x2)>>8;
	blk[2] = (x0+x4)>>8;
	blk[3] = (x8+x6)>>8;
	blk[4] = (x8-x6)>>8;
	blk[5] = (x0-x4)>>8;
	blk[6] = (x3-x2)>>8;
	blk[7] = (x7-x1)>>8;
}

static void imejpeg_idctcol(t_jpeg_dec *jpeg_inst, int * blk)
{
	int x0, x1, x2, x3, x4, x5, x6, x7, x8;
	//intcut
	if (!((x1 = (blk[8*4]<<8)) | (x2 = blk[8*6]) | (x3 = blk[8*2]) |
		(x4 = blk[8*1]) | (x5 = blk[8*7]) | (x6 = blk[8*5]) | (x7 = blk[8*3])))
	{
		blk[8*0]=blk[8*1]=blk[8*2]=blk[8*3]=blk[8*4]=blk[8*5]
		=blk[8*6]=blk[8*7]=jpeg_inst->iclp[(blk[8*0]+32)>>6];
		return;
	}
	x0 = (blk[8*0]<<8) + 8192;
	//first stage
	x8 = W7*(x4+x5) + 4;
	x4 = (x8+(W1-W7)*x4)>>3;
	x5 = (x8-(W1+W7)*x5)>>3;
	x8 = W3*(x6+x7) + 4;
	x6 = (x8-(W3-W5)*x6)>>3;
	x7 = (x8-(W3+W5)*x7)>>3;
	//second stage
	x8 = x0 + x1;
	x0 -= x1;
	x1 = W6*(x3+x2) + 4;
	x2 = (x1-(W2+W6)*x2)>>3;
	x3 = (x1+(W2-W6)*x3)>>3;
	x1 = x4 + x6;
	x4 -= x6;
	x6 = x5 + x7;
	x5 -= x7;
	//third stage
	x7 = x8 + x3;
	x8 -= x3;
	x3 = x0 + x2;
	x0 -= x2;
	x2 = (181*(x4+x5)+128)>>8;
	x4 = (181*(x4-x5)+128)>>8;
	//fourth stage
	blk[8*0] = jpeg_inst->iclp[(x7+x1)>>14];
	blk[8*1] = jpeg_inst->iclp[(x3+x2)>>14];
	blk[8*2] = jpeg_inst->iclp[(x0+x4)>>14];
	blk[8*3] = jpeg_inst->iclp[(x8+x6)>>14];
	blk[8*4] = jpeg_inst->iclp[(x8-x6)>>14];
	blk[8*5] = jpeg_inst->iclp[(x0-x4)>>14];
	blk[8*6] = jpeg_inst->iclp[(x3-x2)>>14];
	blk[8*7] = jpeg_inst->iclp[(x7-x1)>>14];
}

static void imejpeg_fast_idct(t_jpeg_dec *inst, int * block)
{
	Int16 i;

	for (i=0; i<8; i++)
		imejpeg_idctrow(block+8*i);

	for (i=0; i<8; i++)
		imejpeg_idctcol(inst, block+i);
}
static Int32 imejpeg_decode_iqtz_mcu_component_qzblock(t_jpeg_dec *inst, short  *s ,int * d,short flag)
{
	Int16 i,j;
	Int16 tag;
	Int16 *pQt;
	Int32 buffer2[8][8];
	Int32 *buffer1;
	Int16 offset;

	switch(flag)
	{
	case 0:
		pQt = inst->YQtTable;
		offset=128;
		break;
	case 1:
		pQt = inst->UQtTable;
		offset=0;
		break;
	case 2:
		pQt = inst->VQtTable;
		offset=0;
		break;
	}

	for(i=0;i<8;i++)
		for(j=0;j<8;j++){
			tag=imejpeg_Zig_Zag[i][j];
			buffer2[i][j]=(int)s[tag]*(int)pQt[tag];
		}
		buffer1=(int *)buffer2;
		imejpeg_fast_idct(inst, buffer1);
		for(i=0;i<8;i++)
			for(j=0;j<8;j++)
				d[i*8+j]=buffer2[i][j]+offset;
		return 1;
}

static Int32 imejpeg_decode_iqtz_mcu_component(t_jpeg_dec *inst, Int32 flag)
{
	Int16 H,VV;
	Int16 i,j;
	Int32 *pQtZzMCUBuffer;
	Int16  *pMCUBuffer;

	switch(flag)
	{
	case 0:
		H = inst->SampRate_Y_H;
		VV = inst->SampRate_Y_V;
		pMCUBuffer = inst->MCUBuffer;
		pQtZzMCUBuffer = inst->QtZzMCUBuffer;
		break;
	case 1:
		H = inst->SampRate_U_H;
		VV = inst->SampRate_U_V;
		pMCUBuffer = inst->MCUBuffer + inst->Y_in_MCU*64;
		pQtZzMCUBuffer = inst->QtZzMCUBuffer + inst->Y_in_MCU*64;
		break;
	case 2:
		H = inst->SampRate_V_H;
		VV = inst->SampRate_V_V;
		pMCUBuffer = inst->MCUBuffer + ( inst->Y_in_MCU + inst->U_in_MCU)*64;
		pQtZzMCUBuffer = inst->QtZzMCUBuffer + (inst->Y_in_MCU + inst->U_in_MCU)*64;
		break;
	default:
		IMP_Assert(0, "error component");
		break;
	}
	for(i=0;i<VV;i++)
		for (j=0;j<H;j++)
			imejpeg_decode_iqtz_mcu_component_qzblock(inst, pMCUBuffer+(i*H+j)*64,pQtZzMCUBuffer+(i*H+j)*64,flag);
	return 1;
}
static Int32 imejpeg_decode_get_yuv(t_jpeg_dec *inst, Int32 flag)
{
	Int16 H,VV;
	Int16 i,j,k,h;
	Int32 *buf;
	Int32 *pQtZzMCU;

	switch(flag)
	{
	case 0:
		H = inst->SampRate_Y_H;
		VV = inst->SampRate_Y_V;
		buf = inst->Y;
		pQtZzMCU = inst->QtZzMCUBuffer;
		break;
	case 1:
		H = inst->SampRate_U_H;
		VV = inst->SampRate_U_V;
		buf = inst->U;
		pQtZzMCU = inst->QtZzMCUBuffer + inst->Y_in_MCU * 64;
		break;
	case 2:
		H = inst->SampRate_V_H;
		VV = inst->SampRate_V_V;
		buf = inst->V;
		pQtZzMCU = inst->QtZzMCUBuffer + (inst->Y_in_MCU + inst->U_in_MCU) * 64;
		break;
	}
	for (i=0;i<VV;i++)
		for(j=0;j<H;j++)
			for(k=0;k<8;k++)
				for(h=0;h<8;h++)
					buf[(i*8+k)*inst->SampRate_Y_H*8+j*8+h] = *pQtZzMCU++;
	return 1;
}

static Int32 imejpeg_decode_store_buffer(t_jpeg_dec *inst, Int32 linebytes)
{
	Int16 i,j;
	UInt8 R,G,B;
	Int32 y,u,v,rr,gg,bb;
	UInt8 *lpbmp;

	for(i=0; i<inst->SampRate_Y_V*8; i++)
	{
		if((inst->sizei+i) < inst->ImgHeight)
		{
			lpbmp =(UInt8 *)inst->jpg2bmp_buf + i * linebytes + inst->sizej * 3;

			for(j=0;j<inst->SampRate_Y_H*8;j++)
			{
				if((inst->sizej+j) <  inst->ImgWidth)
				{
					y = inst->Y[i * 8 * inst->SampRate_Y_H+j];
					u = inst->U[(i / inst->V_YtoU) * 8 * inst->SampRate_Y_H+j / inst->H_YtoU];
					v = inst->V[(i/inst->V_YtoV) * 8 * inst->SampRate_Y_H+j / inst->H_YtoV];
					rr=((y<<8)+18*u+367*v)>>8;
					gg=((y<<8)-159*u-220*v)>>8;
					bb=((y<<8)+411*u-29*v)>>8;
					R=(UInt8)rr;
					G=(UInt8)gg;
					B=(UInt8)bb;
					if (rr&0xffffff00) if (rr>255) R=255; else if (rr<0) R=0;
					if (gg&0xffffff00) if (gg>255) G=255; else if (gg<0) G=0;
					if (bb&0xffffff00) if (bb>255) B=255; else if (bb<0) B=0;
					*lpbmp++=B;
					*lpbmp++=G;
					*lpbmp++=R;
				}
				else  break;
			}
		}
		else break;
	}
	return 1;
}

static Int32 imejpeg_init_tag_sos(t_jpeg_dec *inst)
{
	Int32 times = 0;
	Int16 llength = imejpeg_get16be(inst);
	Int8 comnum = imejpeg_read_byte(inst);
	if(comnum != inst->comp_num)
		return 0;
	for(Int32 i=0; i<comnum; i++)
	{
		UInt8 temp = imejpeg_read_byte(inst);
		times++;
		if(inst->comp_index[0] == temp)
		{
			Int8 temp = imejpeg_read_byte(inst);
			times++;
			inst->YDcIndex = temp >> 4;
			inst->YAcIndex = (temp&0x0f) + 2;
		}
		else
		{
			Int8 temp = imejpeg_read_byte(inst);
			times++;
			inst->UVDcIndex = temp >> 4;
			inst->UVAcIndex = (temp&0x0f) + 2;
		}
	}
	imejpeg_seek(inst, llength-times-2-1);
	return 1;
}
static Int32 imejpet_init_tag_dht(t_jpeg_dec *inst)
{
	Int32 i, j, k;
	Int16 huftab1, huftab2, huftabindex;
	Int16 llength = imejpeg_get16be(inst);
	if(llength < 0xd0)
	{
		Int16 temp = (Int16)imejpeg_read_byte(inst);
		huftab1 = temp >> 4;
		huftab2 = temp & 0x0f;
		huftabindex = huftab1 * 2 + huftab2;

		for(i=0; i<16; i++)
			inst->code_len_table[huftabindex][i] = (Int16)imejpeg_read_byte(inst);
		j = 0;
		for(i=0; i<16; i++)
			if(inst->code_len_table[huftabindex][i] != 0)
			{
				k = 0;
				while(k < inst->code_len_table[huftabindex][i])
				{
					inst->code_value_table[huftabindex][k+j] = (Int16)imejpeg_read_byte(inst);
					k++;
				}
				j += k;
			}
			i = 0;
			while (inst->code_len_table[huftabindex][i] == 0) 
				i++;
			for(j=0; j<i; j++)
			{
				inst->huf_min_value[huftabindex][j] = 0;
				inst->huf_max_value[huftabindex][j] = 0;
			}
			inst->huf_min_value[huftabindex][i] = 0;
			inst->huf_max_value[huftabindex][i] = inst->code_len_table[huftabindex][i] - 1;
			for(j=i+1; j<16; j++)
			{
				inst->huf_min_value[huftabindex][j]=(inst->huf_max_value[huftabindex][j-1] + 1)<<1;
				inst->huf_max_value[huftabindex][j]=inst->huf_min_value[huftabindex][j] + inst->code_len_table[huftabindex][j] - 1;
			}
			inst->code_pos_table[huftabindex][0]=0;
			for (j=1;j<16;j++)
				inst->code_pos_table[huftabindex][j] = inst->code_len_table[huftabindex][j-1] + inst->code_pos_table[huftabindex][j-1];
	}
	else
	{
		Int32 ccount = 0;
		UInt8 hf_table_index = imejpeg_read_byte(inst);

		while (hf_table_index!=0xff)
		{
			huftab1=(Int16)hf_table_index>>4;     //huftab1=0,1
			huftab2=(Int16)hf_table_index&0x0f;   //huftab2=0,1
			huftabindex=huftab1*2+huftab2;

			ccount = 0;
			for (i=0; i<16; i++)
			{
				inst->code_len_table[huftabindex][i]=(Int16)imejpeg_read_byte(inst);
				ccount += inst->code_len_table[huftabindex][i];
			}
			ccount += 17;	
			j=0;
			for (i=0; i<16; i++)
				if(inst->code_len_table[huftabindex][i]!=0)
				{
					k=0;
					while(k < inst->code_len_table[huftabindex][i])
					{
						inst->code_value_table[huftabindex][k+j] = (Int16)imejpeg_read_byte(inst);
						k++;
					}
					j+=k;
				}
				i=0;
				while (inst->code_len_table[huftabindex][i]==0)
					i++;
				for (j=0;j<i;j++)
				{
					inst->huf_min_value[huftabindex][j] = 0;
					inst->huf_max_value[huftabindex][j] = 0;
				}
				inst->huf_min_value[huftabindex][i] =0;
				inst->huf_max_value[huftabindex][i] = inst->code_len_table[huftabindex][i]-1;
				for (j=i+1;j<16;j++)
				{
					inst->huf_min_value[huftabindex][j] = (inst->huf_max_value[huftabindex][j-1]+1)<<1;
					inst->huf_max_value[huftabindex][j] = inst->huf_min_value[huftabindex][j] + inst->code_len_table[huftabindex][j]-1;
				}
				inst->code_pos_table[huftabindex][0]=0;
				for (j=1;j<16;j++)
					inst->code_pos_table[huftabindex][j] = inst->code_len_table[huftabindex][j-1] + inst->code_pos_table[huftabindex][j-1];

				hf_table_index = imejpeg_read_byte(inst);
		}  //while
	}  //else
	return 1;
}
static Int32 imejpeg_init_tag_sofo(t_jpeg_dec *inst)
{
	Int8 comp_num = 0;
	Int16 llength = imejpeg_get16be(inst);
	imejpeg_read_byte(inst);
	inst->ImgHeight = imejpeg_get16be(inst);
	inst->ImgWidth = imejpeg_get16be(inst);

	comp_num = imejpeg_read_byte(inst);
	inst->comp_num = comp_num;
	if((comp_num != 1)&&(comp_num != 3))
		return 0;
	if(comp_num == 3)
	{
		inst->comp_index[0] = imejpeg_read_byte(inst); //Y
		Int16 temp = (Int16)imejpeg_read_byte(inst); 
		inst->SampRate_Y_H = temp>>4;
		inst->SampRate_Y_V = temp&0x0f;
		temp = (Int16)imejpeg_read_byte(inst);
		inst->YQtTable = inst->qt_table[temp];

		inst->comp_index[1] = imejpeg_read_byte(inst); //U
		temp = (Int16)imejpeg_read_byte(inst); 
		inst->SampRate_U_H = temp>>4;
		inst->SampRate_U_V = temp&0x0f;
		temp = (Int16)imejpeg_read_byte(inst);
		inst->UQtTable = inst->qt_table[temp];

		inst->comp_index[2] = imejpeg_read_byte(inst); //V
		temp = (Int16)imejpeg_read_byte(inst); 
		inst->SampRate_V_H = temp>>4;
		inst->SampRate_V_V = temp&0x0f;
		temp = (Int16)imejpeg_read_byte(inst);
		inst->VQtTable = inst->qt_table[temp];
	}
	else
	{
		UInt8 temp_index = imejpeg_read_byte(inst);
		Int16 temp_samprate = (Int16)imejpeg_read_byte(inst);
		Int16 temp_qttable = (Int16)imejpeg_read_byte(inst);

		inst->comp_index[0] = temp_index; 	
		inst->SampRate_Y_H = temp_samprate>>4;
		inst->SampRate_Y_V = temp_samprate&0x0f;
		inst->YQtTable = inst->qt_table[temp_qttable];

		inst->comp_index[1] = temp_index; //U
		inst->SampRate_U_H = 1;
		inst->SampRate_U_V = 1;
		inst->UQtTable = inst->qt_table[temp_qttable];

		inst->comp_index[2] = temp_index; //V
		inst->SampRate_V_H = 1;
		inst->SampRate_V_V = 1;
		inst->VQtTable = inst->qt_table[temp_qttable];
	}
	return 1;
}

static Int32 imejpeg_init_tag(t_jpeg_dec *inst)
{
	Int16 finish = 0;
	UInt16 id;
	UInt16 llength;
	Int32 qt_table_index;

	while(!finish)
	{
		id = imejpeg_get16be(inst);
		switch(id)
		{
		case M_SOI:
			break;
		case M_APP0:
			{
				llength = imejpeg_get16be(inst);
				for(Int32 i=0; i<5; i++)
				{
					UInt8 jfif_tag = imejpeg_read_byte(inst);
					if(jfif_tag != imejpeg_JFIF_TAG[i])
						return 0;
				}
				imejpeg_seek(inst, llength-2-5);
			}
			break;
		case M_DQT:
			{
				llength = imejpeg_get16be(inst);
				qt_table_index = imejpeg_read_byte(inst)&0x0f;
				if(llength < 80)
				{
					for(Int32 i=0; i<64; i++)
						inst->qt_table[qt_table_index][i] = (Int16)imejpeg_read_byte(inst);
				}
				else
				{
					for(Int32 i=0; i<64; i++)
						inst->qt_table[qt_table_index][i] = (Int16)imejpeg_read_byte(inst);
					qt_table_index = imejpeg_read_byte(inst)&0x0f;
					for(Int32 i=0; i<64; i++)
						inst->qt_table[qt_table_index][i] = (Int16)imejpeg_read_byte(inst);
				}
			}
			break;
		case M_SOF0:
			if(!imejpeg_init_tag_sofo(inst))
				return 0;
			break;
		case M_DHT:
			if(!imejpet_init_tag_dht(inst))
				return 0;
			break;
		case M_SOS:
			if(!imejpeg_init_tag_sos(inst))
				return 0;
			finish = 1;
			break;
		case M_DRI:
			llength = imejpeg_get16be(inst);
			inst->restart = imejpeg_get16be(inst);
			imejpeg_seek(inst, llength-4);
			break;
		case M_EOI:
			finish = 1;
			break;
		default:
			//IMP_Assert(0, "init_tag error id %d\n", id);
			break;
		}
	}
	return 1;
}

static Int32 imejpeg_decode(t_jpeg_dec *inst)
{
	inst->Y_in_MCU = inst->SampRate_Y_H * inst->SampRate_Y_V;
	inst->U_in_MCU = inst->SampRate_U_H * inst->SampRate_U_V;
	inst->V_in_MCU = inst->SampRate_V_H * inst->SampRate_V_V;
	inst->H_YtoU = inst->SampRate_Y_H / inst->SampRate_U_H;
	inst->V_YtoU = inst->SampRate_Y_V / inst->SampRate_U_V;
	inst->H_YtoV = inst->SampRate_Y_H / inst->SampRate_V_H;
	inst->V_YtoV = inst->SampRate_Y_V / inst->SampRate_V_V;
	imejpeg_decode_init_fast_idct(inst);

	Int32 linebytes = WIDTHBYTES(inst->ImgWidth * 24);
	inst->jpg2bmp_buf = (Int8*)IMP_Malloc(16 * linebytes);

	Int32 result;

	while((result=imejpeg_decode_mcu_block(inst)) == 1)
	{
		inst->interval++;
		if((inst->restart)&&(inst->interval % inst->restart==0))
			inst->IntervalFlag=1;
		else
			inst->IntervalFlag=0;
		imejpeg_decode_iqtz_mcu_component(inst, 0);
		imejpeg_decode_iqtz_mcu_component(inst, 1);
		imejpeg_decode_iqtz_mcu_component(inst, 2);
		imejpeg_decode_get_yuv(inst, 0);
		imejpeg_decode_get_yuv(inst, 1);
		imejpeg_decode_get_yuv(inst, 2);
		imejpeg_decode_store_buffer(inst, linebytes);
		inst->sizej += inst->SampRate_Y_H * 8;
		if(inst->sizej >= inst->ImgWidth)
		{
			imepict_jpeg_output(inst, inst->jpg2bmp_buf, 16*linebytes);
			IMP_Memset(inst->jpg2bmp_buf, 0, 16*linebytes);
			inst->sizej = 0;
			inst->sizei += inst->SampRate_Y_V * 8;
		}
		if ((inst->sizej == 0)&&(inst->sizei >= inst->ImgHeight))
			break;
	}
	IMP_Free(inst->jpg2bmp_buf);
	return result;
}

static void ime_set_bmp_param(t_imevui_bitmap_fileheader *fh, t_imevui_bitmap_infoheader *ih, Int32 reserve)
{
	ih->biSize = sizeof(t_imevui_bitmap_infoheader);
	ih->biPlanes = 1;
	ih->biBitCount = 24;
	ih->biCompression = 0;
	ih->biClrUsed = 0;
	ih->biClrImportant = 0;

	Int32 linebytes = WIDTHBYTES(ih->biWidth * ih->biBitCount);
	Int32 imgsize = linebytes * ih->biHeight;

	ih->biSizeImage = imgsize;
	ih->biXPelsPerMeter = 0;
	ih->biYPelsPerMeter = 0;

	fh->bfType = 0x4d42;
	fh->bfSize = sizeof(t_imevui_bitmap_fileheader) + sizeof(t_imevui_bitmap_infoheader) + imgsize;
	//fh->bfOffBits = sizeof(t_imevui_bitmap_fileheader) + sizeof(t_imevui_bitmap_infoheader);  // system display error, so set zero
	fh->bfOffBits = 0;
	fh->bfReserved1 = reserve? IMPICT_BMP_RESERVE1:0;
	fh->bfReserved2 = reserve? IMPICT_BMP_RESERVE2:0;
}

ImpBool impict_jpeg2bmp_file(ImpCStr pathname, ImpStr bmpname)
{
	t_jpeg_dec *jpeg_inst = (t_jpeg_dec *)IMP_Malloc(sizeof(t_jpeg_dec));
	IMP_Memset(jpeg_inst, 0, sizeof(t_jpeg_dec));
	jpeg_inst->dec_type_file = 1;

	ImpFileHandle jpg_fp = IMP_FileOpen(pathname, "rb");
	if(!jpg_fp)
		return IMP_False;
	jpeg_inst->fp = jpg_fp;

	if(!imejpeg_init_tag(jpeg_inst))
	{
		IMP_FileClose(jpg_fp);
		return IMP_False;
	}

	ImpFileHandle bmp_fp = IMP_FileOpen(bmpname, "wb");
	if(!bmp_fp)
	{
		IMP_FileClose(jpg_fp);
		return IMP_False;
	}
	jpeg_inst->out_fp = bmp_fp;

	t_imevui_bitmap_fileheader fh;
	t_imevui_bitmap_infoheader ih;

	ih.biWidth = jpeg_inst->ImgWidth;
	ih.biHeight = jpeg_inst->ImgHeight;

	ime_set_bmp_param(&fh, &ih, 1);
#if defined(MII_BIG_ENDIAN)
	fh.bfType = mii_ltobs(fh.bfType);
	fh.bfSize = mii_ltobl(fh.bfSize);
	fh.bfReserved1 = mii_ltobs(fh.bfReserved1);
	fh.bfReserved2 = mii_ltobs(fh.bfReserved2);
	fh.bfOffBits = mii_ltobl(fh.bfOffBits);

	ih.biSize = mii_ltobl(ih.biSize);
	ih.biWidth = mii_ltobl(ih.biWidth);
	ih.biHeight = mii_ltobl(ih.biHeight);
	ih.biPlanes = mii_ltobs(ih.biPlanes);
	ih.biBitCount = mii_ltobs(ih.biBitCount);
	ih.biCompression = mii_ltobl(ih.biCompression);
	ih.biSizeImage = mii_ltobl(ih.biSizeImage);
	ih.biXPelsPerMeter = mii_ltobl(ih.biXPelsPerMeter);
	ih.biYPelsPerMeter = mii_ltobl(ih.biYPelsPerMeter);
	ih.biClrUsed = mii_ltobl(ih.biClrUsed);
	ih.biClrImportant = mii_ltobl(ih.biClrImportant);	
#endif	
	IMP_FileWrite((Int8 *)&fh, 14, bmp_fp);
	IMP_FileWrite((Int8 *)&ih, 40, bmp_fp);

	Int32 ret = imejpeg_decode(jpeg_inst);
	IMP_FileClose(jpg_fp);
	IMP_FileClose(bmp_fp);

	IMP_Free(jpeg_inst);
	return IMP_True;
}

ImpBool impict_png2bmp_file(ImpCStr pngName, ImpCStr bmpName)
{
	Int8 *img_p = 0;
	Int32 img_w = 0, img_h = 0;

	impict_png_init();
	impict_png_decode(pngName, &img_p, &img_w, &img_h);

	ImpFileHandle bmp_fp = IMP_FileOpen(bmpName, "wb");
	if(!bmp_fp)
	{
		impict_png_deinit();
		return IMP_False;
	}
	t_imevui_bitmap_fileheader fh;
	t_imevui_bitmap_infoheader ih;

	ih.biWidth = img_w;
	ih.biHeight = img_h;

	ime_set_bmp_param(&fh, &ih, 0);

#if defined(MII_BIG_ENDIAN)
	fh.bfType = mii_ltobs(fh.bfType);
	fh.bfSize = mii_ltobl(fh.bfSize);
	fh.bfReserved1 = mii_ltobs(fh.bfReserved1);
	fh.bfReserved2 = mii_ltobs(fh.bfReserved2);
	fh.bfOffBits = mii_ltobl(fh.bfOffBits);

	ih.biSize = mii_ltobl(ih.biSize);
	ih.biWidth = mii_ltobl(ih.biWidth);
	ih.biHeight = mii_ltobl(ih.biHeight);
	ih.biPlanes = mii_ltobs(ih.biPlanes);
	ih.biBitCount = mii_ltobs(ih.biBitCount);
	ih.biCompression = mii_ltobl(ih.biCompression);
	ih.biSizeImage = mii_ltobl(ih.biSizeImage);
	ih.biXPelsPerMeter = mii_ltobl(ih.biXPelsPerMeter);
	ih.biYPelsPerMeter = mii_ltobl(ih.biYPelsPerMeter);
	ih.biClrUsed = mii_ltobl(ih.biClrUsed);
	ih.biClrImportant = mii_ltobl(ih.biClrImportant);	
#endif	
	
	IMP_FileWrite((Int8 *)&fh, 14, bmp_fp);
	IMP_FileWrite((Int8 *)&ih, 40, bmp_fp);

	Int8 *pBufLine = (Int8*)IMP_Malloc(img_w*3);
	for(Int32 y=img_h-1; y>=0; y--)
	{
		Int8 *buf0 = ((Int8*)img_p) + y*img_w*3;
		Int8 *buf1 = pBufLine;
		for(Int32 x=0; x<img_w; x++)
		{
			*buf1++ = buf0[x*3+2];
			*buf1++ = buf0[x*3+1];
			*buf1++ = buf0[x*3+0];
		}
		IMP_FileWrite(pBufLine, img_w*3, bmp_fp);
	}
	IMP_Free(pBufLine);
	IMP_FileClose(bmp_fp);

	impict_png_deinit();
	return IMP_True;
}

Int32 impict_jpeg_init(void)
{
	t_jpeg_dec *jpeg_inst = (t_jpeg_dec*)IMP_Malloc(sizeof(t_jpeg_dec));
	return (Int32)jpeg_inst;
}

void impict_jpeg_deinit(Int32 inst)
{
	t_jpeg_dec *jpeg_inst = (t_jpeg_dec *)inst;
	if(jpeg_inst)
	{
		if(jpeg_inst->out_buf)
			IMP_Free(jpeg_inst->out_buf);
		IMP_Free(jpeg_inst);
	}
}

ImpBool impict_jpeg_decode(Int32 inst, Int8 *jpeg_data, Int32 jpeg_len, Int8 **rgb24_buf, Int32 *w, Int32 *h)
{
	t_jpeg_dec *jpeg_inst = (t_jpeg_dec *)inst;
	IMP_Memset(jpeg_inst, 0, sizeof(t_jpeg_dec));
	jpeg_inst->dec_type_file = 0;
	jpeg_inst->in_buf = jpeg_data;
	jpeg_inst->in_len = jpeg_len;

	imejpeg_init_tag(jpeg_inst);

	jpeg_inst->out_buf = (Int8*)IMP_Malloc(jpeg_inst->ImgWidth*jpeg_inst->ImgHeight*3);

	Int32 ret = imejpeg_decode(jpeg_inst);

	*w = jpeg_inst->ImgWidth;
	*h = jpeg_inst->ImgHeight;
	*rgb24_buf = jpeg_inst->out_buf;
	return IMP_True;
}

